#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <algorithm>
#include <string>
#include <vector>
#include "tile.h"
#include "node.h"
#include "constants.h"
#include "types.h"
#include "SDL/SDL_image.h"

SDL_Surface *load_image(std::string filename);

void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL, bool relative = true);

bool check_collision(SDL_Rect A, SDL_Rect B);

bool pointInBox(SDL_Rect box, position pos);

double distance(double x1, double y1, double x2, double y2);

int calculate_dir(double sx, double tx, double sy, double ty);

bool touches_wall(SDL_Rect box, Tile *tiles[][MAP_WIDTH]);

bool init();

bool video_init();

void clean_up();

bool set_tiles(Tile *tiles[][MAP_WIDTH], std::string filename);

void draw_box(int x, int y, int w, int h, Uint32 color, bool fill, bool relative = true);

void draw_line(int x1, int y1, int x2, int y2, Uint32 color); // ei kai toimi

void draw_hline(int x, int y, int w, Uint32 color);

void draw_vline(int x, int y, int h, Uint32 color);

short x_to_tile(float x);

short y_to_tile(float y);

int tile_to_x(short x);

int tile_to_y(short y);

void sha256(char *string, char outputBuffer[65]);

bool line_of_sight(int x1, int y1, int x2, int y2);

std::vector<position> find_path(int startX, int startY, int flagX, int flagY, bool full);

struct DereferenceCompareNode : public std::binary_function<Node, Node, bool>
{
    bool operator()(const Node lhs, const Node rhs) const
    {
        return lhs.f > rhs.f;
    }
};

template <class T, class Compare> class PQV : public std::vector<T> {
    private:
        Compare comp;
        bool sorted;
        void assureHeap() {
            if (sorted) {
                make_heap(this->begin(),this->end(), comp);
                sorted = false;
            }
        }
    public:
        PQV(Compare cmp = Compare()) : comp(cmp) {
            make_heap(this->begin(),this->end(), comp);
            sorted = false;
        }

        const T& top() {
            assureHeap();
            return this->front();
        }

        void push(const T& x) {
            assureHeap();
            this->push_back(x);
            push_heap(this->begin(),this->end(), comp);
        }

        void pop() {
            assureHeap();
            pop_heap(this->begin(),this->end(), comp);
            this->pop_back();
        }

        void sort() {
            if(not sorted) {
                sort_heap(this->begin(),this->end(), comp);
                //reverse(this->begin(),this->end());
                sorted = true;
            }
        }
};

#endif // FUNCTIONS_H
